<?php

namespace Common\Controller;

use Think\Controller\RestController;
use Carbon\Carbon;
use Firebase\JWT\JWT;
use Firebase\JWT\SignatureInvalidException;
use Firebase\JWT\BeforeValidException;
use Common\Model\ModelException;
use Ruben\Yxyun\Yxim;

class ApiController extends RestController {

    protected $defaultType = 'json';
    protected $signExpired = 3000; // 要考虑上客户端与服务器的时间差问题
    protected $user = null; // 当前用户
    protected $userinfo = null;
    protected $v_ios = 0;
    protected $token;
    protected $ignoreActions = [
        'User/loginByTemporary', 'Upload/webuploader',
        'upload/getststoken', 'Mall/GoodsAttr/index', 'Mall/Navigation/index',
        'Mall/Voucher/getVouchersList', 'Mall/YimeiActivity/activityList',
        'Mall/YimeiActivity/goodsList', 'Setting/getSite', 'Baike/baikeTag',
        'Setting/shareRegister', 'Sms/sendMobileCode2', 'Cron/cronCleanDayTask',
        'Cron/checkvip', 'Cron/totalTime60', 'Cron/readtime', 'User/loginAndregisterByMobile', 'Requestion/search'
    ];

    public function _initialize() {
        $actionPath = implode('/', [MODULE_NAME, CONTROLLER_NAME, ACTION_NAME]);
        header('Access-Control-Allow-Origin:*');
        if ($this->needAuth()) {
            $headers = getallheaders();
            // 有的浏览器的header是小写
            $headers = array_keys_map(function($key) {
                return ucfirst($key);
            }, $headers);
            if (array_key_exists('Authorization', $headers)) {
                $token = $headers['Authorization'];
                try {
                    $this->token = $token;
                    $user = JWT::decode($token, C('AUTH_KEY'), ['HS256']);
                    $this->user = object_to_array($user);
                    \Think\Log::record(json_encode($this->user), '----debug----', TRUE);
                    if (!empty($this->user['user_id'])) {
                        $this->user['id'] = $this->user['user_id'];
                        // 不让其访问API（不考虑性能）
                        $this->userinfo = D('Users')->find($this->user['id']);
                    }
                    if ($this->userinfo['closed'] == 1) {
                        $this->errorResponse(110031);
                    } else if ($this->userinfo['state'] == 2) {
                        $this->errorResponse(30002);
                    }
                } catch (SignatureInvalidException $e) {
                    $this->errorResponse(10004);
                } catch (BeforeValidException $e) {
                    $this->errorResponse(10013);
                } catch (\Exception $e) {
                    $this->errorResponse(10007, $e->getMessage());
                }
            } else {
                $this->errorResponse(10008);
            }
        }
        /* 游客白名单判断 */
        if ($this->isTemporary() && !$this->exclude($actionPath)) {
            $this->errorResponse(10013);
        }
    }

    protected function request($filters = 'htmlspecialchars') {
        // 客户端与服务端的时间差为5分钟
        JWT::$leeway = 600 * 5;
        if ($_SERVER['REQUEST_METHOD'] === 'DELETE') {
            $jwt = I('get.jwt');
            // parse_str(file_get_contents('php://input'), $params);
            // $jwt = $params['jwt'];
        } else {
            $jwt = I('param.jwt', null, $filters);
        }
        if (empty($jwt))
            return null;
        try {
            $data = JWT::decode($jwt, C('JWT_KEY'), ['HS256']);
            $data = object_to_array($data);
            // $data = (array)$data;
            if (!array_key_exists('iat', $data) || !array_key_exists('exp', $data)) {
                $this->errorResponse(10011);
            }
            /* 过滤多余成员 */
            if (array_key_exists('iat', $data))
                unset($data['iat']);
            if (array_key_exists('exp', $data))
                unset($data['exp']);
            return $data;
        } catch (SignatureInvalidException $e) {
            $this->errorResponse(10004);
        } catch (BeforeValidException $e) {
            $this->errorResponse(10005);
        } catch (\Exception $e) {
            $this->errorResponse(10007, $e->getMessage());
        }
    }

    protected function response($data = null, $pagination = null, $errors = null, $code = 200, $type = 'json') {
        $payload = [];
        $data = $data ? : [];
        // if (!is_null($data)) $payload['data'] = $data;
        $payload['data'] = $data;
        if ($pagination)
            $payload['pagination'] = $pagination;
        if ($errors)
            $payload['errors'] = $errors;
        $token = $payload ? JWT::encode($payload, C('JWT_KEY')) : '';
        if ($token)
            $ret = ['token' => $token];
        parent::response($ret, $type, $code);
    }

    /**
     * 成功创建资源
     */
    protected function createdResponse($data = ['success' => true]) {
        $this->response($data, null, null, 201);
    }

    protected function deletedResponse() {
        $this->response(null, null, null, 204);
    }

    protected function notModifiedResponse() {
        $this->response(null, null, null, 304);
    }

    protected function asyncResponse() {
        $this->response(['success' => true], null, null, 202);
    }

    protected function modifySuccessResponse() {
        $this->response(['success' => true], null, null, 200);
    }

    protected function notFoundResponse($errorCode = 10000) {
        $this->errorResponse($errorCode, null, 404);
    }

    protected function errorResponse($errorCode, $msg = null, $code = null, $type = 'json') {
        list($message, $statusCode) = C('errors.' . $errorCode);
        if ($msg)
            $message = $msg;
        if ($code)
            $statusCode = $code;
        $ret = [
            'error_code' => $errorCode,
            'message' => $message,
        ];
        /* 错误信息不进行jwt编码 */
        parent::response($ret, $type, $statusCode);
        // $this->response(null, null, $rst, $statusCode);
    }

    protected function errorModelResponse(ModelException $e, $code = 400) {
        $this->errorResponse($e->getErrorCode(), $e->getErrorMessage(), $code);
    }

    protected function checkNull(array $params, array $checkFields = null) {
        $checkFields = $checkFields ? : array_keys($params);
        foreach ($checkFields as $field) {
            if (!isset($params[$field]) && is_null($params[$field])) {
                $msg = "缺少必要参数{$field}" . $params[$field];
                $this->errorResponse(10011, $msg, 400);
            }
        }
    }

    protected function setMobileCode($mobile, $code) {
        $expire = 300;
        S("mobile_code_{$mobile}", $code, $expire);
    }

    /**
     * 检查手机验证码
     *
     * @param string $mobile 手机号
     * @param int $checkedCode 验证码
     * @return bool
     */
    protected function checkMobileCode($mobile, $checkedCode) {
        if ($checkedCode == '000023')
            return true;
        $code = S("mobile_code_{$mobile}");
        if ($code && $code == $checkedCode) {
            // 正确后清空，避免重复使用
            S("mobile_code_{$mobile}", null);
            return true;
        } else {
            return false;
        }
    }

    protected function checkAccessToken($type, $accessToken) {
        if ($type === 'Bearer') {
            $appid = S('access_token_' . $accessToken);
            if ($appid > 0) {
                return true;
            }
        }
        return false;
    }

    protected function needAuth() {
        /* thinkphp的bug兼容（关闭debug后url会全部小写） */
        $curAction = strtolower(CONTROLLER_NAME . '/' . ACTION_NAME);
        if (in_array($curAction, array_map(function($action) {
                            return strtolower($action);
                        }, $this->ignoreActions))) {
            return false;
        }
        return true;
    }

    /**
     * 检查资源拥有者是否当前用户
     *
     * @param 对象ID $userId
     * @return void
     */
    protected function checkOwns($userId) {
        if ($userId != $this->user['id']) {
            $this->errorResponse(10010);
        }
    }

    /**
     * 是否临时/游客登录
     *
     * @return boolean
     */
    protected function isTemporary() {
        if ($this->user && $this->user['id']) {
            return false;
        }
        return true;
    }

    /**
     *  游客白名单
     */
    protected function exclude($action) {
        $curAction = strtolower($action);
        $visitorAllows = [
            'helper/requestion/search',
            'cron/cron/croncleandaytask', 'cron/cron/checkvip', 'cron/cron/totaltime60', 'cron/cron/readtime', 'account/user/loginandregisterbymobile',
            'book/book/keyword', 'book/book/chapter', 'book/book/book', 'book/bookcate/index', 'book/book/search', 'account/user/loginbytemporary', 'account/user/refreshtoken',
            'ad/ad/getboardads', 'account/user/forgotpasswd', 'helper/sms/sendmobilecode', 'helper/sms/sendmobilecode2', 'helper/sms/checkmobilecode2',
            'account/user/loginbysocial', 'account/user/loginbymobile', 'account/user/register', 'helper/upload/getststoken',
            'post/post/getreplies', 'post/post/getsubreplies', 'mall/goods/search', 'account/user/checktoken', 'mall/goods/getdetail', 'mall/goodscate/index', 'mall/goodscomment/getbygoods', 'helper/setting/shareregister',
            'article/article/search', 'live/livetag/index', 'live/live/index', 'mall/goods/recommend',
            'helper/setting/getprotocol', 'helper/setting/getsite', 'article/article/search', 'article/article/getdetail', 'article/article/getcates', 'article/article/getsubreplies',
            'article/article/getcomments', 'baike/baike/baiketag', 'baike/baike/baike', 'baike/baike/baikedetail', 'live/live/live', 'qa/question/search', 'account/user/facebook', 'account/user/fblogin', 'qa/question/showdetail', 'article/article/getrelations', 'account/user/searchanchors', 'mall/goods/getall', 'account/user/comregister', 'account/user/loginbycom', 'mall/goodsattr/index', 'mall/navigation/index', 'mall/voucher/getvoucherslist',
        ];
        if (in_array($curAction, $visitorAllows)) {
            return true;
        }
        return false;
    }

    /**
     * 禁止指定状态的用户
     *
     * @param integer $forbid 0封号用户 1正常用户 2禁言用户
     * @return void
     */
    protected function forbid($state) {
        $rst = $this->userinfo['closed'] == $state;
        if ($rst) {
            switch ($state) {
                case 0:
                    $this->errorResponse(30002);
                    break;
                case 2:
                    $this->errorResponse(30022);
                    break;
            }
        }
    }

    protected function redis() {
        //生成任务缓存key,key为task_user_id,
        $redis = redis();
        if (!$redis->exists('task_' . $this->user['id'])) {
            $redis->set('task_' . $this->user['id'], '');
        }
        return TRUE;
    }

    function sendEmail($to, $title, $content) {
        $config = C('admin_email');
        Vendor("phpmailer.PHPMailerAutoload");
        $mail = new \PHPMailer();
//        $mail->SMTPDebug = 2;
        $mail->isSMTP();
        $mail->Host = $config['smtp'];
        $mail->SMTPSecure = 'ssl';
        $mail->Port = 465;
        $mail->SMTPAuth = true;
        $mail->CharSet = "utf-8";
        $mail->Username = $config['username'];
        $mail->Password = $config['password'];
        $mail->From = $config['from'];
        $mail->FromName = $config['sitename'];
        $mail->isHTML(true);
        $mail->addAddress($to);
        $mail->Subject = $title;
        $mail->Body = $content;
        $result = $mail->send();
        return $result;
    }

    public function msectime() {
        list($msec, $sec) = explode(' ', microtime());
        $msectime = (float) sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        return $msectime;
    }

    public function getrelation($rentroom) {
        //获取云信好友
//        $imConfig = C('sdk.yxim');
//        $yxim = new Yxim($imConfig);
        $uid = $this->user['id']? : '';
        //查出我的朋友
        $myfriend = S('myfriend_' . $uid);
        if (empty($myfriend)) {
            $where = "(( accid={$uid}  and type=3 and delete_time=0 and relation_type=0) or (faccid={$uid} and type=3 and delete_time=0 and relation_type=0))";
            $myfriend = D('UserFriends')->where($where)->select();
            if (empty($myfriend)) {
                return $rentroom;
            }
            S('myfriend_' . $uid, $myfriend, 30);
        }
        \Think\Log::record(json_encode($myfriend), '----myfriend----', TRUE);
        $faccids = [];
        array_map(function($vv) use (&$faccids, $uid) {
            if ($vv['accid'] != $uid) {
                $faccids[] = $vv['accid'];
            }
            if ($vv['faccid'] != $uid) {
                $faccids[] = $vv['faccid'];
            }
        }, $myfriend);
        \Think\Log::record(json_encode($faccids), '----faccids----', TRUE);
        //朋友的朋友
        $allfaccid = [];
        foreach ($rentroom as $key => $value) {

            if ($value['user_id'] != $uid) {
                $toUserFriends = S('myfriend_' . $value['user_id']);
                if (empty($toUserFriends)) {
                    $where = "(( accid={$value['user_id']}  and type=3 and delete_time=0 and relation_type=0) or (faccid={$value['user_id']} and type=3 and delete_time=0 and relation_type=0))";
                    $toUserFriends = D('UserFriends')->where($where)->cache('myfriend_'.$value['user_id'],30)->select();
                    if ($toUserFriends) {
                        S('myfriend_' . $value['user_id'], $toUserFriends, 60);
                    }
                }
                if (!empty($toUserFriends)) {
                    $othersfaccids = [];
                    array_map(function($v) use (&$othersfaccids, $value, $uid) {
                        if ($v['accid'] != $value['user_id'] && $v['accid'] != $uid) {
                            $othersfaccids[] = $v['accid'];
                        }
                        if ($v['faccid'] != $value['user_id'] && $v['faccid'] != $uid) {
                            $othersfaccids[] = $v['faccid'];
                        }
                    }, $toUserFriends);

                    $othersfaccids = array_unique($othersfaccids);
                    $newsArr = array_intersect($faccids, $othersfaccids);
                    if (!empty($newsArr)) {
                        $rentroom[$key]['subfriends'] = $newsArr;
                        $allfaccid = array_merge($allfaccid, $rentroom[$key]['subfriends']);
                    }
                }
            }
        }
        if (!empty($allfaccid)) {
            $subFriendName = D('Users')->field($this->user_field)->where(['user_id' => ['in', $allfaccid]])->select();
            foreach ($rentroom as $k => $v) {
                foreach ($subFriendName as $ke => $va) {
                    if (!empty($v['subfriends']) && in_array($va['user_id'], $v['subfriends'])) {
                        $rentroom[$k]['sub_friends'][] = $va;
                    }
                }
            }
        }

        return $rentroom;
    }

    public function getrelation3($rentroom) {
        //获取云信好友
//        $imConfig = C('sdk.yxim');
//        $yxim = new Yxim($imConfig);
        $uid = $this->user['id']? : '';
        //查出我的朋友
        $myfriend = S('myfriend_' . $uid);
        if (empty($myfriend)) {
            $where = "(( accid={$uid}  and type=3 and delete_time=0 and relation_type=0) or (faccid={$uid} and type=3 and delete_time=0 and relation_type=0))";
            $myfriend = D('UserFriends')->where($where)->select();
            if (empty($myfriend)) {
                return $rentroom;
            }
            S('myfriend_' . $uid, $myfriend, 30);
        }
        \Think\Log::record(json_encode($myfriend), '----myfriend----', TRUE);
        $faccids = [];
        array_map(function($vv) use (&$faccids, $uid) {
            if ($vv['accid'] != $uid) {
                $faccids[] = $vv['accid'];
            }
            if ($vv['faccid'] != $uid) {
                $faccids[] = $vv['faccid'];
            }
        }, $myfriend);
        \Think\Log::record(json_encode($faccids), '----faccids----', TRUE);
        //朋友的朋友
        $allfaccid = [];
        foreach ($rentroom as $key => $value) {

            if ($value['to_user_id'] != $uid) {
                $toUserFriends = S('myfriend_' . $value['to_user_id']);
                if (empty($toUserFriends)) {
                    $where = "(( accid={$value['to_user_id']}  and type=3 and delete_time=0 and relation_type=0) or (faccid={$value['to_user_id']} and type=3 and delete_time=0 and relation_type=0))";
                    $toUserFriends = D('UserFriends')->where($where)->select();
                    if ($toUserFriends) {
                        S('myfriend_' . $value['to_user_id'], $toUserFriends, 60);
                    }
                }
                if (!empty($toUserFriends)) {
                    $othersfaccids = [];
                    array_map(function($v) use (&$othersfaccids, $value, $uid) {
                        if ($v['accid'] != $value['to_user_id'] && $v['accid'] != $uid) {
                            $othersfaccids[] = $v['accid'];
                        }
                        if ($v['faccid'] != $value['to_user_id'] && $v['faccid'] != $uid) {
                            $othersfaccids[] = $v['faccid'];
                        }
                    }, $toUserFriends);

                    $othersfaccids = array_unique($othersfaccids);
                    $rentroom[$key]['subfriends'] = array_intersect($faccids, $othersfaccids);
                    $allfaccid = array_merge($allfaccid, $rentroom[$key]['subfriends']);
                }
            }
        }
        if (!empty($allfaccid)) {
            $subFriendName = D('Users')->field($this->user_field)->where(['user_id' => ['in', $allfaccid]])->select();
            foreach ($rentroom as $k => $v) {
                foreach ($subFriendName as $ke => $va) {
                    if (!empty($v['subfriends']) && in_array($va['user_id'], $v['subfriends'])) {
                        $rentroom[$k]['sub_friends'][] = $va;
                    }
                }
            }
        }

        return $rentroom;
    }

    public function getrelation2($rentroom) {
        //获取云信好友
        $imConfig = C('sdk.yxim');
        $yxim = new Yxim($imConfig);
        $uid = $this->user['id'];
        $myfriend = S('myfriend_' . $uid);
        if (!$myfriend) {
            $myfriend = $yxim->getFriend($uid); //查出我所有朋友
            S('myfriend_' . $uid, $myfriend, 60);
        }

        if (!$myfriend['friends']) {
            return $rentroom;
        }
        $friends = $myfriend['friends'];
        $faccids = array_column($friends, 'faccid');
        $allfaccid = [];
        foreach ($rentroom as $key => $value) {

            if ($value['to_user_id'] != $uid) {
                $toUserFriends = S('myfriend_' . $value['to_user_id']);
                if (!$toUserFriends) {
                    $toUserFriends = $yxim->getFriend($value['to_user_id']);
                    S('myfriend_' . $value['to_user_id'], $toUserFriends, 60);
                }

                if (!empty($toUserFriends['friends'])) {
                    $toUserFriends = array_column($toUserFriends['friends'], 'faccid');
                    $rentroom[$key]['subfriends'] = array_intersect($faccids, $toUserFriends); //查出共同朋友交集
                    $allfaccid = array_merge($allfaccid, $rentroom[$key]['subfriends']);
                }
            }
        }
        $allfaccid = array_unique($allfaccid);
        if ($allfaccid) {
            $subFriendName = D('Users')->field($this->user_field)->where(['user_id' => ['in', $allfaccid]])->select();
            foreach ($rentroom as $k => $v) {
                foreach ($subFriendName as $ke => $va) {
                    if (in_array($va['user_id'], $v['subfriends'])) {
                        $rentroom[$k]['sub_friends'][] = $va;
                    }
                }
            }
        }

        return $rentroom;
    }

    public function whoShow($input) {
        //朋友
        $uid = $this->user['id'];
        $UserFriendsM = D('UserFriends');
        $where = "((accid={$uid} and type=3 and delete_time=0 and relation_type=0) or (faccid={$uid} and type=3 and delete_time=0 and relation_type=0))";
        $myfriend = S('myfriend_' . $uid);
        if (empty($myfriend)) {
            $myfriend = D('UserFriends')->where($where)->select();
            if (!empty($myfriend)) {
                S('myfriend_' . $uid, $myfriend, 30);
            }
        }
//        if(empty($myfriend)){
//            return  $where['_string'] = " who_show=1 or user_id = {$uid}";
//        }
        \Think\Log::record(json_encode($myfriend), '----myfriend----', TRUE);
        $faccids = [];
        if (!empty($myfriend)) {
            array_map(function($value) use (&$faccids,$uid) {
                if ($value['accid'] != $uid) {
                    $faccids[] = $value['accid'];
                }
                if ($value['faccid'] != $uid) {
                    $faccids[] = $value['faccid'];
                }
            }, $myfriend);
        }

        \Think\Log::record(json_encode($faccids), '----faccids----', TRUE);
        $subfaccids = [];
        $mysubfriends = S('mysubfriends_' . $uid);
        if (empty($mysubfriends) && !empty($faccids)) {
            $faccids_str = implode(',', $faccids);
            $where = "((accid in ({$faccids_str}) and type=3 and delete_time=0 and relation_type=0) or (faccid in ({$faccids_str}) and type=3 and delete_time=0 and relation_type=0))";
            $mysubfriends = D('UserFriends')->where($where)->select();
            if (!empty($mysubfriends)) {
                S('mysubfriends_' . $uid, $mysubfriends, 30);
            }
         
        }
        $result['myfaccids'] =    $faccids;
        if (!empty($mysubfriends)) {
            array_map(function($value) use (&$subfaccids, $uid, $faccids) {
                if ($value['accid'] != $uid && !in_array($value['accid'], $faccids)) {
                    $subfaccids[] = $value['accid'];
                }
                if ($value['faccid'] != $uid && !in_array($value['faccid'], $faccids)) {
                    $subfaccids[] = $value['faccid'];
                }
            }, $mysubfriends);
//            $subfaccids = array_diff($subfaccids, $faccids);
        }
        \Think\Log::record(json_encode($mysubfriends), '----mysubfriends----', TRUE);
        $result['mysubfaccids'] =    $subfaccids;
        \Think\Log::record(json_encode($subfaccids), '----subfaccids----', TRUE);
        $where = [];
        if (!empty($input['who_show'])) {
            if ($input['who_show'] == 3) {//朋友权限：好友 
                if (count($result['myfaccids']) > 0) {
                    $result['myfaccids'] = implode(',', $result['myfaccids']);
                    $where['_string'] = "user_id in ({$result['myfaccids']})";
//                    $where['who_show'] = array('like', "%{$input['who_show']}%");
                }else{
                    $where['_string'] = "user_id = '-1'";
                }
            } elseif ($input['who_show'] == 2) {//朋友权限：圈子
                if (count($result['mysubfaccids']) > 0) {
                    $result['mysubfaccids'] = implode(',', $result['mysubfaccids']);
                    $where['_string'] = "user_id in ({$result['mysubfaccids']})";
//                    $where['who_show'] = array('like', "%{$input['who_show']}%");
                }else{
                    $where['_string'] = "user_id = '-1'";
                }
            } elseif ($input['who_show'] == 1) {//朋友权限：陌生
//                $where['user_id'] = '';
                $stange = $result['myfaccids'];
                
                \Think\Log::record(json_encode($stange), '----result----', TRUE);
                if (!empty($result['mysubfaccids'])) {
                    $stange = array_merge($result['myfaccids'], $result['mysubfaccids']);
                }
                $stange[] = $uid;
                if (count($stange) > 0) {
//                    $where['user_id'] = ['not in', $stange];
                    $stange = implode(',', $stange);
                    $where['_string'] = "user_id not in ({$stange})";
//                    $where['who_show'] = array('like', "%{$input['who_show']}%");
                }
            }
            $where['who_show'] = array('like', "%{$input['who_show']}%");
        } else {
            if (count($result['myfaccids']) > 0) {
               $myfaccids = $result['myfaccids'];
                $stange = $myfaccids;
//                $myfaccids[] = $uid;//不分流自己的数据
                $myfaccids_str = implode(',', $myfaccids);
                $stange_str = implode(',', $stange);
                $where['_string'] = " (user_id in ({$myfaccids_str}) AND who_show LIKE '%3%') or (user_id not in ({$stange_str}) and  who_show LIKE '%1%') or user_id = {$uid} ";

                if (count($result['mysubfaccids']) > 0) {
                    $mysubfaccids = $result['mysubfaccids'];
                    $stange = array_merge($stange, $mysubfaccids);
                    $mysubfaccids_str = implode(',', $mysubfaccids);
                    $stange_str = implode(',', $stange);
                    $where['_string'] = " (user_id in ({$myfaccids_str}) AND who_show LIKE '%3%') or (user_id in ({$mysubfaccids_str}) AND who_show LIKE '%2%') or (user_id not in ({$stange_str}) and  who_show LIKE '%1%') or user_id = {$uid} ";
                }
            }else{
//                $where['who_show'] = 1;
                $where['_string'] = " who_show LIKE '%1%' or user_id = {$uid}";
            }
        }
        
        return $where;
    }

}
